

#include "accountmgr.h"

#include "coid/comm/binstream/filestream.h"
#include "coid/comm/binstream/textstream.h"

namespace coid {


////////////////////////////////////////////////////////////////////////////////
opcd AccountMgr::add_account( net_in account& acid, bool modify )
{
    if( modify == false )
    {
        const account* pac = _accounts.find_value(acid);
        if(pac)
            return ersALREADY_EXISTS;

        acid._uniqid = _acid++;
        _accounts.insert_value(acid);
    }
    else
    {
        const account* pac = _accounts.find_value(acid);
        if(!pac)
            return ersNO_MATCH;
        //we don't change the hash key, so we can cast
        ((account*)pac)->_pwd = acid._pwd;
        ((account*)pac)->_perm = acid._perm;
    }

    save();

    return 0;
}

////////////////////////////////////////////////////////////////////////////////
opcd AccountMgr::del_account( net_in const charstr& name, net_in const charstr& key )
{
    account_id acid;
    acid._name = name;
    acid._domain = key;

    return  _accounts.erase(acid) > 0  ?  opcd(0)  :  ersNOT_FOUND;
}

////////////////////////////////////////////////////////////////////////////////
opcd AccountMgr::list_accounts( net_out dynarray<account>& data ) const
{
    uints n = _accounts.size();
    data.need_new(n);
    
    t_hash::const_iterator cb = _accounts.begin();
    t_hash::const_iterator ce = _accounts.end();

    for( uint i=0; cb != ce; ++cb, ++i )
    {
        data[i]._name = (*cb)._name;
        data[i]._domain = (*cb)._domain;
        data[i]._perm = (*cb)._perm;
        data[i]._uniqid = (*cb)._uniqid;
        data[i]._pwd.nullpwd();
    }

    return 0;
}

////////////////////////////////////////////////////////////////////////////////
opcd AccountMgr::find_account( net_inout account& acid ) const
{
    const account* pac = _accounts.find_value( acid );
    if(pac)
    {
        if( acid._pwd != pac->_pwd )  return ersINVALID_LOGIN_PASSWORD;
        acid._perm = pac->_perm;
        acid._uniqid = pac->_uniqid;
        return 0;
    }
    return ersINVALID_LOGIN_NAME;
}

////////////////////////////////////////////////////////////////////////////////
opcd AccountMgr::save() const
{
    bofstream bof(".accounts");
    if( !bof.is_open() )  return ersIO_ERROR;

    metastream meta;
    fmtstreamcxx txp(bof);
    meta.bind_formatting_stream(txp);    

    meta.stream_out( _accounts );
    //meta.get_binstream() << _accounts;
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
opcd AccountMgr::load()
{
    bifstream bif(".accounts");

    if( bif.is_open() )
    {
        metastream meta;
        fmtstreamcxx txp(bif);
        meta.bind_formatting_stream(txp);    

        t_hash acc;

        opcd e=0;
        try { meta.stream_in( acc ); }
        //try { meta.get_binstream() >> acc; }
        catch(opcd exc) { e = exc; }

        if( !e && acc.size() > 0 )
        {
            _acid = (uint)acc.size();
            _accounts.swap(acc);
            return e;
        }
    }

    bif.close();

    _acid = 0;
    account acid;
    acid._name = "root";
    acid._perm._flags = account_perm::fPERM_MANAGE_ACCOUNTS;
    add_account( acid );
    
    return 0;
}


} //namespace coid
